package com.atguigu.udmp.web.userprofile.service.impl;

import com.alibaba.fastjson.JSON;

import com.atguigu.udmp.web.common.util.RedisUtil;
import com.atguigu.udmp.web.userprofile.bean.TagCondition;
import com.atguigu.udmp.web.userprofile.bean.TagInfo;
import com.atguigu.udmp.web.userprofile.bean.UserGroup;
import com.atguigu.udmp.web.userprofile.constant.ConstCodes;
import com.atguigu.udmp.web.userprofile.mapper.UserGroupMapper;
import com.atguigu.udmp.web.userprofile.service.TagInfoService;
import com.atguigu.udmp.web.userprofile.service.UserGroupService;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;


import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhangchen
 * @since 2021-05-04
 */
@Service
@Slf4j
@DS("udmp")
public class UserGroupServiceImpl extends ServiceImpl<UserGroupMapper, UserGroup> implements UserGroupService {

    @Autowired
    TagInfoService tagInfoService;

    @Override
    public void saveUserGroupInfo(UserGroup userGroup) {
         //1 把条件集合转储成json
        List<TagCondition> tagConditionList = userGroup.getTagConditions();
        String conditionJsonStr = JSON.toJSONString(tagConditionList);
        userGroup.setConditionJsonStr(conditionJsonStr);

        // 2 把条件中的中文提取出来
        String conditionComment = userGroup.conditionToComment();
        userGroup.setConditionComment(conditionComment);
        // 3 创建日期
        userGroup.setCreateTime(new Date());



        // 4 保存到mysql中
        super.saveOrUpdate(userGroup);

    }

    /**
     * 写入doris
     * 1 先清理已有的usergroup
     * 2 再新增usergroup
     * @param userGroup
     */
    @Override
    public void genUserGroup(UserGroup userGroup) {


        //   清理已有的userGroup
        baseMapper.deleteUserGroup(userGroup.getId().toString());

        //执行sql
        String insertSelectSQL = getInsertSelectSQL(userGroup);
        super.baseMapper.insertBitmapSQL(insertSelectSQL);
        System.out.println(insertSelectSQL);
    }



    // 拼接成完整insert select 语句
    public  String getInsertSelectSQL(UserGroup userGroup){

        String bitmapUnionAll = getBitmapUnionSQL(userGroup);
        String insertSQL="insert into  user_group select     '"+userGroup.getId()+"', bitmap_intersect(bm.uids) as  uids from ("+bitmapUnionAll+") bm";

        return  insertSQL;
    }

    //负责生成bitmapUnionSQL
    //把多个子查询用union all拼接起来

    //   subquery1
    //     union all
    //   subquery2
    //     union all
    //   subquery3
    //     union all
    //     ....
    public  String getBitmapUnionSQL(UserGroup userGroup){
        List<TagCondition> tagConditionList = userGroup.getTagConditions();
        List<Long> tagIdList = tagConditionList.stream().map(tagCondition -> tagCondition.getTagId()).collect(Collectors.toList());

        Map<Long, TagInfo> tagInfoMapWithCode = tagInfoService.getTagInfoMap(tagIdList);
        String busiDate=userGroup.getBusiDate();
        StringBuilder  sqlBuilder=new StringBuilder();
        for (TagCondition tagCondition : tagConditionList) {
            //获得新的子查询sql
            String subQuerySQL = getConditionSubQuerySQL(tagCondition, tagInfoMapWithCode, busiDate);
            //判断 如果是builder中没有值 ，则不用拼接把  subquerySQL直接写入builder中
            //    如果builder有值，不是第一条   bitmapAnd(+ builder中的sql+ , +新的子查询 +)
            if(sqlBuilder.length()> 0){
                sqlBuilder.append("union all") ;
            }
            sqlBuilder .append(subQuerySQL);
        }
        return sqlBuilder.toString();

    }

    //单独一个条件 生成一个子查询sql
    ////select bitmap_union(us) from user_tag_value_string  where  tag_id= 12
    //            and  tag_value in ('70后','80后','90后') and  dt='2020-06-14'
    //
    //// 1  tag_id :  tagId
    //// 2  表名 ： 要根据标签值的类型确定  标签值类型 用tagcode 去查询mysql 的标签定义  tag_info
    //// 3  operator ： 把页面传过来的英文 进行转义
    //// 4  tag_value :    tagValues   1 多个 进行拼接 用逗号分割 2 依据标签值类型 来决定是否加单引 3 根据 in 或者 not in 来决定是否加小括号
    //// 5  dt   : busidate
    public String  getConditionSubQuerySQL(TagCondition tagCondition ,Map<Long,TagInfo> tagInfoMap,String busiDate){
        //1 tag_id
        Long tagId = tagCondition.getTagId();

        //2 确定表名
        TagInfo tagInfo = tagInfoMap.get(tagId);
        String tagValueType = tagInfo.getTagValueType();
        String tableName="";
        if(tagValueType.equals(ConstCodes.TAG_VALUE_TYPE_STRING)){
            tableName="user_tag_bitmap_string";
        }else if(tagValueType.equals(ConstCodes.TAG_VALUE_TYPE_DECIMAL)){
            tableName="user_tag_bitmap_decimal";
        }

        //3  operator ： 把页面传过来的英文 进行转义 操作符
        String operator=getConditionOperator(tagCondition.getOperator());
        //// 4 tag_value :    tagValues   1 多个 进行拼接 用逗号分割 2 依据标签值类型 来决定是否加单引 3 根据 in 或者 not in 来决定是否加小括号

        String tagValueSQL = "";

        if(tagValueType.equals(ConstCodes.TAG_VALUE_TYPE_STRING) ){
            tagValueSQL = "'"+StringUtils.join(tagCondition.getTagValues(), "','")+"'";
        }else{
            tagValueSQL = StringUtils.join(tagCondition.getTagValues(), ",");
        }

        if(tagCondition.getOperator().equals("in")||tagCondition.getOperator().equals("nin")){
            tagValueSQL= "("+tagValueSQL+")";
        }

        // 5  dt   : busidate
        String dt=busiDate;


        //6 组合子查询
        String subquerySQL="(select bitmap_union(uids) " +
                " from   " +tableName+
                " where  tag_id="+tagId+"\n" +
                "  and  tag_value  "+operator+" " +tagValueSQL+
                " and  dt='"+dt+"' ) ";

        System.out.println(subquerySQL);
        return subquerySQL;
    }



    private  String getConditionOperator(String operator){
        switch (operator){
            case "eq":
                return "=";
            case "lte":
                return "<=";
            case "gte":
                return ">=";
            case "lt":
                return "<";
            case "gt":
                return ">";
            case "neq":
                return "<>";
            case "in":
                return "in";
            case "nin":
                return "not in";
        }
        throw  new RuntimeException("操作符不正确");
    }


    @Override
    public Long saveToRedis(UserGroup userGroup) {
        // 1  得到分群的计算结果   查询doris
        String[] uidArr=   super.baseMapper.selectUidList(userGroup.getId().toString());

        // 2  把计算结果（人群包) 保存到 redis中

        Jedis jedis = RedisUtil.getJedis();
        String userGroupKey="user_group:"+userGroup.getId();
        // 清理已有的usergroup
        jedis.del(userGroupKey);

        jedis.sadd(userGroupKey,uidArr);

        jedis.close();

        return uidArr.length+0L;

    }

    @Override
    public Long getUserGroupNum(UserGroup userGroup) {
       // 1  组合sql   获得bitmapUnionAll  拼接 select  ( bitmapAndSQL ) ;
        String BitmapUnionSQL = getBitmapUnionSQL(userGroup);
        String userGroupNumSQL=" select bitmap_count(bitmap_intersect(bu.uids)) ct from ( "+BitmapUnionSQL+" ) bu";

        // 2  执行该sql 获得Long结果
        Long userGroupNum = baseMapper.selectUserGroupNum(userGroupNumSQL);

        return userGroupNum;
    }

    /**
     * 根据主键查询usergroup基本信息
     * @param userGroupId
     * @param busiDate
     * @return
     */
    @Override
    public UserGroup getUserGroupInfo(String userGroupId, String busiDate) {
        UserGroup userGroup = getById(userGroupId);
        String conditionJsonStr = userGroup.getConditionJsonStr();
        List<TagCondition> tagConditionList = JSON.parseArray(conditionJsonStr, TagCondition.class);
        userGroup.setTagConditions(tagConditionList);
        userGroup.setBusiDate(busiDate);
        return userGroup;
    }


}
